/*
 *
 * Copyright (c) 2023 - future
 * @author fzh
 * @email e_341877120_mail@163.com
 * @link https://mvnrepository.com/search?q=io.github.xrfzh.cn
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package cn.xrfzh.biz.video.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.xrfzh.api.userVideoInteraction.vo.InteractionNumberVo;
import cn.xrfzh.api.video.dto.VideoQueryDto;
import cn.xrfzh.biz.userVideoInteraction.mapper.UserVideoInteractionMapper;
import cn.xrfzh.common.utils.R;
import cn.xrfzh.qiniuyun.service.QiniuyunFileService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import cn.xrfzh.common.utils.XrPageUtil;
import cn.xrfzh.common.redis.RedisCacheClient;
import cn.xrfzh.common.redis.annotation.ClearRedisCache;
import cn.xrfzh.common.utils.XrObjectUtil;
import cn.xrfzh.common.axios.AxiosEnum;
import cn.xrfzh.common.axios.AxiosResult;
import cn.xrfzh.common.exception.MyCustomException;
import cn.xrfzh.common.utils.ParallelStreamUtil;
import cn.xrfzh.biz.video.mapper.VideoMapper;
import cn.xrfzh.api.video.pojo.Video;
import cn.xrfzh.api.video.dto.VideoDto;
import cn.xrfzh.biz.video.service.IVideoService;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 用于存储视频信息
 *
 * @author fzh
 * @email e_341877120_mail@163.com
 * @date 2023-10-24 08:34:41
 */
@Service
@Transactional
@RequiredArgsConstructor
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements IVideoService {

    private final RedisCacheClient redisCacheClient;

    private final QiniuyunFileService qiniuyunFileService;

    private final UserVideoInteractionMapper userVideoInteractionMapper;

    /**
     * 根据内容分类查询对应类别的视频（不分页）
     *
     * @param videoQueryDto
     * @return
     */
    @Override
    public AxiosResult selectList(VideoQueryDto videoQueryDto) {
        LambdaQueryWrapper<Video> lqw;
        if (XrObjectUtil.checkOfAllNull(videoQueryDto)) {
            lqw = null;
        } else {
            lqw = new LambdaQueryWrapper<>();
            // 构建内容分类查询构造器
            lqw.eq(Video::getCategoryId, videoQueryDto.getCategoryId());
        }
        List<Video> videoList = redisCacheClient.queryAllFromRedisIfExists("video", 1800L,
                TimeUnit.SECONDS, Video.class, lqw, this::list);
        boolean flag = ObjectUtils.isNotEmpty(videoList);
        return flag ? AxiosResult.selectSuccess(videoList) : AxiosResult.selectError();
    }

    /**
     * 根据内容分类查询对应类别的视频（分页）
     *
     * @param currentPage
     * @param pageSize
     * @param videoDto
     * @return
     */
    @Override
    public AxiosResult selectPage(int currentPage, int pageSize, VideoDto videoDto) {
        LambdaQueryWrapper<Video> lqw;
        if (XrObjectUtil.checkOfAllNull(videoDto)) {
            lqw = null;
        } else {
            lqw = new LambdaQueryWrapper<>();
            // 构建内容分类查询构造器
            lqw.eq(Video::getCategoryId, videoDto.getCategoryId());
        }
        XrPageUtil xrPageUtil = redisCacheClient.queryByPageFromRedisIfExists("video", 1800L, TimeUnit.SECONDS,
                currentPage, pageSize, lqw, this::list);
        boolean flag = ObjectUtils.isNotEmpty(xrPageUtil);
        return flag ? AxiosResult.selectSuccess(xrPageUtil) : AxiosResult.selectError();
    }

    /**
     * 根据id查询单个
     *
     * @param id
     * @return
     */
    @Override
    public AxiosResult selectOneById(Long id) {
        if (ObjectUtils.isNotEmpty(id)) {
            Video video = getById(id);
            boolean flag = ObjectUtils.isNotEmpty(video);
            return flag ? AxiosResult.selectSuccess(video) : AxiosResult.selectError();
        }
        throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
    }

    /**
     * 用户发布视频
     *
     * @param videoDto
     * @return
     */
    @ClearRedisCache("video")
    @Override
    public AxiosResult insert(VideoDto videoDto) {
        if (ObjectUtils.isNotEmpty(videoDto)) {
            Video video = new Video();
            BeanUtils.copyProperties(videoDto, video);
            // 设置上传日期
            video.setUploadDate(new Date());
            // 设置视频上传者ID
            video.setUploaderId(StpUtil.getLoginIdAsInt());
            boolean flag = save(video);
            return flag ? AxiosResult.insertSuccess() : AxiosResult.insertError();
        }
        throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
    }

    /**
     * 更新
     *
     * @param videoDto
     * @return
     */
    @ClearRedisCache("video")
    @Override
    public AxiosResult update(VideoDto videoDto) {
        if (ObjectUtils.isNotEmpty(videoDto)) {
            boolean flag = updateById(null);
            return flag ? AxiosResult.updateSuccess() : AxiosResult.updateError();
        }
        throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
    }

    /**
     * 根据id删除单个
     *
     * @param id
     * @return
     */
    @ClearRedisCache("video")
    @Override
    public AxiosResult delete(Long id) {
        if (ObjectUtils.isNotEmpty(id)) {
            boolean flag = removeById(id);
            return flag ? AxiosResult.deleteSuccess() : AxiosResult.deleteError();
        }
        throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
    }

    /**
     * 根据id集合批量删除
     *
     * @param idList
     * @return
     */
    @ClearRedisCache("video")
    @Override
    public AxiosResult deleteBatch(List<Long> idList) {
        if (ObjectUtils.isEmpty(idList) || idList.size() == 0) {
            throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
        }
        boolean flag = removeByIds(idList);
        return flag ? AxiosResult.deleteSuccess() : AxiosResult.deleteError();
    }

    /**
     * 导入文件
     *
     * @param file
     * @return
     */
    @ClearRedisCache("video")
    @Override
    public AxiosResult importFile(MultipartFile file) {
        boolean flag = false;
        try {
            InputStream inputStream = file.getInputStream();
            ExcelReader er = ExcelUtil.getReader(inputStream);
            List<Video> videoList = er.readAll(Video.class);
            flag = ParallelStreamUtil.insertBatchOfLarge(videoList, baseMapper::insertBatch);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag ? AxiosResult.success(AxiosEnum.IMPORT_SUCCESS) : AxiosResult.error(AxiosEnum.IMPORT_ERROR);
    }

    /**
     * 导出文件
     *
     * @param response
     */
    @Override
    public void exportFile(HttpServletResponse response) {
        try {
            List<Video> videoList = list();
            ExcelWriter ew = ExcelUtil.getWriter(true);
            ew.setOnlyAlias(true);
            ew.write(videoList);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            String fileName = URLEncoder.encode("Excel导出表", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            ServletOutputStream sos = response.getOutputStream();
            ew.flush(sos, true);
            sos.close();
            IoUtil.close(sos);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 上传视频
     *
     * @param file
     * @return
     */
    @Override
    public AxiosResult uploadVideo(MultipartFile file) {
        R r = qiniuyunFileService.uploadFile(file);
        String videoUrl = MapUtil.getStr(r, R.DATA);
        return AxiosResult.success(AxiosEnum.UPLOAD_SUCCESS, videoUrl);
    }

    /**
     * 查询当前视频的点赞量和收藏量
     *
     * @param videoId
     * @return
     */
    @Override
    public AxiosResult getInteractionNumber(int videoId) {
        Integer likedNumber = userVideoInteractionMapper.getLikedNumber(videoId);
        Integer favoriteNumber = userVideoInteractionMapper.getFavoriteNumber(videoId);
        return AxiosResult.selectSuccess(new InteractionNumberVo().setLikedNumber(null != likedNumber ? likedNumber : 0)
                .setFavoriteNumber(null != favoriteNumber ? favoriteNumber : 0)
        );
    }

}
